package cn.com.sparkle.paxos.userserver;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

import com.google.protobuf.ByteString;

import cn.com.sparkle.paxos.AccountBook;
import cn.com.sparkle.paxos.addprocess.AddRequestDealer;
import cn.com.sparkle.paxos.addprocess.AddRequestPackage;
import cn.com.sparkle.paxos.iomodel.protobuffmessage.PaxosMessages.AddResponse;
import cn.com.sparkle.paxos.iomodel.protobuffmessage.PaxosMessages.MessagePackage;
import cn.com.sparkle.paxos.net.factory.NetCloseException;
import cn.com.sparkle.paxos.net.factory.PaxosSession;
import cn.com.sparkle.paxos.stablestorage.ReadSuccessRecordCallback.SuccessfulRecordWrap;

public abstract class UserHandlerInterface {
	private final static Logger logger = Logger
			.getLogger(UserHandlerInterface.class);
	private AddRequestDealer addRequestDealer;

	/*
	 * public UserHandlerInterface(AddRequestDealer addRequestDealer){
	 * this.addRequestDealer = addRequestDealer; }
	 */

	public abstract void onClientConnect(PaxosSession session);

	public abstract void onClientCustomCommandReceive(
			PaxosSession session, MessagePackage messagePackage);

	public abstract void onClientClose(PaxosSession session);
	
	public void onLoged(SuccessfulRecordWrap successfulRecordWrap,
			long instanceId, List<ByteString> customCommand, AccountBook aBook)
			throws IOException {
		ArrayList<byte[]> customResult = new ArrayList<byte[]>(
				customCommand.size());
		for (ByteString bs : customCommand) {
			customResult.add(new byte[0]);
		}
		finishLogedProcess(successfulRecordWrap, customResult);
		writeExecuteLog(instanceId,aBook);
	}

	public final void setAddRequestDealer(AddRequestDealer addRequestDealer) {
		this.addRequestDealer = addRequestDealer;
	}

	public final void log(MessagePackage messagePackage,
			PaxosSession session)
			throws NotPermissionLogOnMasterExeception {
		if (messagePackage.getAddRequest().getTransportMaster()
				|| messagePackage.getAddRequest().getIsManagerCommand()) {
			addRequestDealer.add(messagePackage, session);
		} else {
			throw new NotPermissionLogOnMasterExeception(
					"this commad can't be log because of the isTransportMaster is false");
		}
	}
	/**
	 * this will finish command ,and clear callback function in client
	 * @param session
	 * @param requestMessagePackage
	 * @param response
	 */
	public final void finishCustomCommand(PaxosSession session,
			MessagePackage requestMessagePackage, AddResponse response) {
//		MessagePackage.Builder messagePackage = MessagePackage.newBuilder();
//		messagePackage.setId(requestMessagePackage.getId());
//		messagePackage.setIsLast(true);
//		messagePackage.setAddResponse(response);
//		try {
//			session.writeObject(messagePackage.build());
//		} catch (SessionHavaClosedException e) {
//		}
		sendMessage(session,requestMessagePackage,response,true);
	}
	
	/**
	 * this will can send data to client continously ,and unclear callback function in client
	 * @param session
	 * @param requestMessagePackage
	 * @param response
	 */
	
	public final void sendNotifyMessage(PaxosSession session,
			MessagePackage requestMessagePackage, AddResponse response){
		sendMessage(session,requestMessagePackage,response,false);
	}
	private void sendMessage(PaxosSession session,
			MessagePackage requestMessagePackage, AddResponse response,boolean isLast){
		MessagePackage.Builder messagePackage = MessagePackage.newBuilder();
		messagePackage.setId(requestMessagePackage.getId());
		messagePackage.setIsLast(isLast);
		messagePackage.setAddResponse(response);
		try {
			session.write(messagePackage.build());
		} catch (NetCloseException e) {
		}
	}

	public final void finishLogedProcess(SuccessfulRecordWrap recordWrap, ArrayList<byte[]> customResult)
			throws IOException {
		if (recordWrap.getAddRequestPackages() != null) {
			// send add response
			LinkedList<AddRequestPackage> addRequestPackages = recordWrap
					.getAddRequestPackages();
			int resultIndex = 0;
			AddResponse.Builder addResponseBuilder = AddResponse.newBuilder();
			for (AddRequestPackage arp : addRequestPackages) {
				for (ByteString bb : arp.valueList) {
					ByteString bs = ByteString.copyFrom(customResult
							.get(resultIndex));
					addResponseBuilder.setResult(bs);
					AddResponse response = addResponseBuilder.build();
					arp.response(response);
				}
			}
		}
	}
	public final void writeExecuteLog(long instanceId,AccountBook aBook) throws IOException{
		try {
			aBook.finishCurInstance(instanceId);
		} catch (IOException e) {
			logger.error("fatal error", e);
			throw e;
		}
	}
}
